#!/bin/bash
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh

# Generators don't have logging right now
# https://github.com/systemd/systemd/issues/15638
exec 1>/dev/kmsg; exec 2>&1

command -v getarg >/dev/null || . /usr/lib/dracut-lib.sh

set -e

UNIT_DIR="${1:-/tmp}"

add_requires() {
    local name="$1"; shift
    local target="$1"; shift
    local requires_dir="${UNIT_DIR}/${target}.requires"
    mkdir -p "${requires_dir}"
    ln -sf "../${name}" "${requires_dir}/${name}"
}

if ! is-live-image; then
    exit 0
fi

# Create stamp file that everything else should use to detect a live boot
> /run/ostree-live

add_requires sysroot.mount     initrd-root-fs.target
add_requires sysroot-etc.mount initrd-root-fs.target
add_requires sysroot-var.mount initrd-root-fs.target

mkdir -p "${UNIT_DIR}/ostree-prepare-root.service.d"
cat > "${UNIT_DIR}/ostree-prepare-root.service.d/10-live.conf" <<EOF
# With live PXE there's no ostree= argument on the kernel command line, so
# we need to find the tree path and pass it to ostree-prepare-root.  But
# ostree-prepare-root only knows how to read the path from
# /proc/cmdline, so we need to synthesize the proper karg and bind-mount
# it over /proc/cmdline.
# https://github.com/ostreedev/ostree/issues/1920

[Unit]
# The base unit conditions on the ostree karg, which won't exist until
# ExecStartPre runs
ConditionKernelCommandLine=

[Service]
ExecStartPre=/usr/sbin/ostree-cmdline start
ExecStartPost=/usr/sbin/ostree-cmdline stop
EOF

isoroot=$(getarg coreos.liveiso= ||:)
if [ -z "${isoroot}" ]; then
    # In this case, the rootfs is already unpacked into the initrd, or we need
    # to retrieve it
    cat >"${UNIT_DIR}/sysroot.mount" <<EOF
# Automatically generated by live-generator

[Unit]
DefaultDependencies=false
# Verifies that we have the right root.squashfs, or downloads it if needed
After=coreos-livepxe-rootfs.service
Before=initrd-root-fs.target

[Mount]
What=/root.squashfs
Where=/sysroot
Type=squashfs
Options=loop
EOF
else
    # And in this case, it's on the ISO
    mkdir -p /run/media/iso
    isosrc=dev/disk/by-label/${isoroot}
    isosrc_escaped=$(systemd-escape -p --suffix=device "${isosrc}")
    initrd_rootdev_target_d="${UNIT_DIR}"/initrd-root-device.target.d
    mkdir -p "${initrd_rootdev_target_d}"
    cat > "${initrd_rootdev_target_d}/50-root-device.conf" <<EOF
[Unit]
After=${isosrc_escaped}
Requires=${isosrc_escaped}
EOF
    cat >"${UNIT_DIR}/run-media-iso.mount" <<EOF
# Automatically generated by live-generator

[Unit]
DefaultDependencies=false
# HACK for https://github.com/coreos/fedora-coreos-config/issues/437
Wants=systemd-udev-settle.service
# Note that bootup(7) implies that initrd-root-device is After=basic.target
# but that appears to not be the case.  We explicitly order after sysinit.target
After=sysinit.target
After=initrd-root-device.target
Before=initrd-root-fs.target

[Mount]
What=/${isosrc}
Where=/run/media/iso
Options=ro
Type=iso9660
EOF

    cat >"${UNIT_DIR}/sysroot.mount" <<EOF
# Automatically generated by live-generator

[Unit]
DefaultDependencies=false
Before=initrd-root-fs.target
RequiresMountsFor=/run/media/iso

[Mount]
What=/run/media/iso/images/pxeboot/rootfs.img
Where=/sysroot
Type=squashfs
# Offset of the squashfs within the rootfs cpio.  Assumes newc format
# and that a file named "root.squashfs" is the first member.  This offset
# is checked by coreos-assembler cmd-buildextend-live at build time.
Options=loop,offset=124
EOF
fi

# It turns out that `tmpfs` currently munches all SELinux labels
# we set before policy is loaded, so we make an XFS filesystem
# loopback mounted that's sized the same as /run.
# https://github.com/coreos/fedora-coreos-config/pull/499
cat >"${UNIT_DIR}/sysroot-xfs-ephemeral-mkfs.service" <<'EOF'
[Unit]
DefaultDependencies=false
# Let's be sure we have basic devices, but other than that we
# can run really early.
After=systemd-tmpfiles-setup-dev.service
ConditionPathExists=/usr/lib/initrd-release
# Something seems to be causing us to rerun?
ConditionPathExists=!/run/ephemeral

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c 'set -euo pipefail; mem=$$(($$(stat -f -c "%%b * %%s / 1024" /run))) && /bin/truncate -s $${mem}k /run/ephemeral.xfsloop'
ExecStart=/sbin/mkfs.xfs /run/ephemeral.xfsloop
ExecStart=/bin/mkdir /run/ephemeral
EOF
add_requires sysroot-xfs-ephemeral-mkfs.service initrd-root-fs.target

cat >>"${UNIT_DIR}/run-ephemeral.mount" <<EOF
[Unit]
DefaultDependencies=false
Requires=sysroot-xfs-ephemeral-mkfs.service
After=sysroot-xfs-ephemeral-mkfs.service
[Mount]
What=/run/ephemeral.xfsloop
Where=/run/ephemeral
Type=xfs
Options=loop,discard
EOF

cat >"${UNIT_DIR}/sysroot-xfs-ephemeral-setup.service" <<EOF
[Unit]
DefaultDependencies=false
RequiresMountsFor=/run/ephemeral
ConditionPathExists=/usr/lib/initrd-release
ConditionPathExists=!/run/ephemeral/var
# Make sure /sysroot is mounted first, since we're mounting under there
Requires=sysroot.mount
After=sysroot.mount
# And after OSTree has set up the chroot() equivalent
After=ostree-prepare-root.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/cp -a /sysroot/etc /run/ephemeral/etc
ExecStart=/bin/mkdir /run/ephemeral/var
EOF

common_etcvar_unit() {
    cat << EOF
# Automatically generated by live-generator
[Unit]
DefaultDependencies=false
# Make sure our tmpfs is available
Requires=sysroot-xfs-ephemeral-setup.service
After=sysroot-xfs-ephemeral-setup.service
# We're part of assembling the root fs
Before=initrd-root-fs.target
EOF
}

common_etcvar_unit > "${UNIT_DIR}/sysroot-etc.mount"
cat >>"${UNIT_DIR}/sysroot-etc.mount" <<EOF
[Mount]
What=/run/ephemeral/etc
Where=/sysroot/etc
Type=none
Options=bind
EOF
add_requires sysroot-etc.mount initrd-root-fs.target

common_etcvar_unit >"${UNIT_DIR}/sysroot-var.mount"
cat >>"${UNIT_DIR}/sysroot-var.mount" <<EOF
[Mount]
What=/run/ephemeral/var
Where=/sysroot/var
Type=none
Options=bind
EOF
add_requires sysroot-var.mount initrd-root-fs.target

cat >>"${UNIT_DIR}/sysroot-relabel.service" <<EOF
[Unit]
DefaultDependencies=false
RequiresMountsFor=/sysroot/etc /sysroot/var
Before=initrd-root-fs.target
[Service]
Type=oneshot
RemainAfterExit=yes
# We don't need the full relabeling spam by default for these
StandardOutput=null
ExecStart=/bin/coreos-relabel /etc
ExecStart=/bin/coreos-relabel /var
EOF
add_requires sysroot-relabel.service initrd-root-fs.target
